package com.wholesmart.common.security.crypto;

import java.util.Base64;
import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 基于Base64和盐密码位运算的加密解密工具（前端配合使用CryptoJS.js）
 * 
 * @author dyw
 * @date 2019年12月16日
 */

public class CipherCrypto implements Crypto {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	private static String double_equal_sign = "==";

	public CipherCrypto() {
		super();
		logger.info("浏览器安全模块启用CipherCrypto加密解密器，注意使用Cipher加密传输密码");
	}

	@Override
	public String decode(String... objs) {
		if (objs != null) {
			return decodeProcess(objs[0]);
		}
		return null;
	}

	@Override
	public String encoder(String... objs) {
		if (objs != null) {
			return encoderProcess(objs[0], objs[1]);
		}
		return null;
	}

	/**
	 * 解码
	 * 
	 * @param password
	 * @param salt
	 * @return
	 */
	private String decodeProcess(String obj) {
		String[] arr = splicePasswordAndSalt(obj);
		return decryptAESExpand(arr[0], arr[1], arr[1]);
	}

	/**
	 * 加密
	 * 
	 * @param password
	 * @param salt
	 * @return
	 */
	private String encoderProcess(String obj, String salt) {
		return encryptAESExpand(obj, salt, salt);
	}

	/**
	 * 拆分密码和盐
	 * 
	 * @param passwordSalt
	 * @return
	 */
	private String[] splicePasswordAndSalt(String passwordSalt) {
		String[] arr = passwordSalt.split(double_equal_sign);
		arr[0] = arr[0] + double_equal_sign;
		return arr;
	}

	/**
	 * 加密
	 * 
	 * @param data
	 * @return
	 */
	private String encryptAESExpand(String data, String key, String iv) {
		try {
			Cipher cipher = Cipher.getInstance("AES/CBC/NOPadding"); // 参数分别代表 算法名称/加密模式/数据填充方式
			int blockSize = cipher.getBlockSize();
			byte[] dataBytes = data.getBytes();
			int plaintextLength = dataBytes.length;
			if (plaintextLength % blockSize != 0) {
				plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
			}
			byte[] plaintext = new byte[plaintextLength];
			System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
			cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
			byte[] encrypted = cipher.doFinal(plaintext);
			String encode = Base64.getEncoder().encodeToString(encrypted);
			// 如果数据过长base64会自动添加换行符
			encode = encode.replaceAll(System.lineSeparator(), "");
			return getUUID(3) + encode;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 解密
	 * 
	 * @param data
	 * @return
	 */
	private String decryptAESExpand(String data, String key, String iv) {
		try {
			data = data.substring(3);
			byte[] encrypted1 = Base64.getDecoder().decode(data);
			Cipher cipher = Cipher.getInstance("AES/CBC/NOPadding");
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
			byte[] original = cipher.doFinal(encrypted1);
			String originalString = new String(original);
			return originalString;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 获取16位的UUID
	 * 
	 * @return
	 */
	private String getUUID(int num) {
		UUID uuid = UUID.randomUUID();
		return uuid.toString().replaceAll("-", "").substring(0, num);
	}
}
